ãã³ãã¬ãŒããªãã©ã«åãæ¡ä»¶åãªã©ãTypeScriptã®é«åºŠãªæ©èœã掻çšããŠããã衚çŸåè±ãã§ä¿å®ããããã³ãŒããèšè¿°ããæ¹æ³ãæ¢æ±ããŸããè€éãªã·ããªãªã§ã®åæäœãç¿åŸããŸãããã
TypeScriptã®é«åºŠãªåïŒãã³ãã¬ãŒããªãã©ã«åãšæ¡ä»¶åããã¹ã¿ãŒãã
TypeScriptã®åŒ·ã¿ã¯ãã®åŒ·åãªåã·ã¹ãã ã«ãããŸããstringãnumberãbooleanã®ãããªåºæ¬çãªåã¯å€ãã®ã·ããªãªã§ååã§ããããã³ãã¬ãŒããªãã©ã«åãæ¡ä»¶åã®ãããªé«åºŠãªæ©èœã¯ã衚çŸåãšåå®å
šæ§ã®æ°ããªã¬ãã«ãåãéããŸãããã®ã¬ã€ãã§ã¯ããããã®é«åºŠãªåã®æ©èœãæ¢æ±ããå®éã®ã¢ããªã±ãŒã·ã§ã³ã瀺ããªãããå
æ¬çãªæŠèŠãæäŸããŸãã
ãã³ãã¬ãŒããªãã©ã«åã®çè§£
ãã³ãã¬ãŒããªãã©ã«åã¯JavaScriptã®ãã³ãã¬ãŒããªãã©ã«ãåºã«ããŠãããæååã®è£éã«åºã¥ããŠåãå®çŸ©ã§ããŸããããã«ãããç¹å®ã®æååãã¿ãŒã³ã衚ãåãäœæã§ããã³ãŒããããå ç¢ã§äºæž¬å¯èœãªãã®ã«ããããšãã§ããŸãã
åºæ¬çãªæ§æãšäœ¿çšæ³
ãã³ãã¬ãŒããªãã©ã«åã¯ãJavaScriptã®ãã³ãã¬ãŒããªãã©ã«ãšåæ§ã«ãããã¯ã¯ã©ãŒãïŒ`ïŒã䜿çšããŠåå®çŸ©ãå²ã¿ãŸããããã¯ã¯ã©ãŒãå
ã§ã¯ã${}æ§æã䜿çšããŠä»ã®åãè£éã§ããŸããããã«éæ³ããããŸããæ¬è³ªçã«ãè£éå
ã®åã«åºã¥ããŠã³ã³ãã€ã«æã«æ§ç¯ãããæååã®åãäœæããŠããã®ã§ãã
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
type APIEndpoint = `/api/${string}`;
// Example Usage
const getEndpoint: APIEndpoint = "/api/users"; // Valid
const postEndpoint: APIEndpoint = "/api/products/123"; // Valid
const invalidEndpoint: APIEndpoint = "/admin/settings"; // TypeScript will not show an error here as `string` can be anything
ãã®äŸã§ã¯ãAPIEndpointã¯/api/ã§å§ãŸãä»»æã®æååã衚ãåã§ãããã®åºæ¬çãªäŸãæçšã§ããããã³ãã¬ãŒããªãã©ã«åã®çã®åã¯ãããå
·äœçãªåå¶çŽãšçµã¿åããããšãã«çŸããŸãã
ãŠããªã³åãšã®çµã¿åãã
ãã³ãã¬ãŒããªãã©ã«åã¯ããŠããªã³åãšäœµçšãããšç䟡ãçºæ®ããŸããããã«ãããç¹å®ã®æååã®çµã¿åããã衚ãåãäœæã§ããŸãã
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
type APIPath = "users" | "products" | "orders";
type APIEndpoint = `/${APIPath}/${HTTPMethod}`;
// Valid API Endpoints
const getUsers: APIEndpoint = "/users/GET";
const postProducts: APIEndpoint = "/products/POST";
// Invalid API Endpoints (will result in TypeScript errors)
// const invalidEndpoint: APIEndpoint = "/users/PATCH"; // Error: "/users/PATCH" is not assignable to type "/users/GET" | "/users/POST" | "/users/PUT" | "/users/DELETE" | "/products/GET" | "/products/POST" | ... 3 more ... | "/orders/DELETE".
ããã§ãAPIEndpointã¯APIãã¹ãšHTTPã¡ãœããã®ç¹å®ã®çµã¿åããã®ã¿ãèš±å¯ãããããå¶éçãªåã«ãªããŸãããTypeScriptã¯ç¡å¹ãªçµã¿åããã䜿çšããããšãã詊ã¿ãæ€åºããåå®å
šæ§ãé«ããŸãã
ãã³ãã¬ãŒããªãã©ã«åã«ããæååæäœ
TypeScriptã«ã¯ããã³ãã¬ãŒããªãã©ã«åãšã·ãŒã ã¬ã¹ã«é£æºããçµã¿èŸŒã¿ã®æååæäœåãçšæãããŠããŸãããããã®åã䜿çšãããšãã³ã³ãã€ã«æã«æååã倿ã§ããŸãã
- Uppercase: æååã倧æåã«å€æããŸãã
- Lowercase: æååãå°æåã«å€æããŸãã
- Capitalize: æååã®æåã®æåã倧æåã«ããŸãã
- Uncapitalize: æååã®æåã®æåãå°æåã«ããŸãã
type Greeting = "hello world";
type UppercaseGreeting = Uppercase; // "HELLO WORLD"
type LowercaseGreeting = Lowercase; // "hello world"
type CapitalizedGreeting = Capitalize; // "Hello world"
type UncapitalizedGreeting = Uncapitalize; // "hello world"
ãããã®æååæäœåã¯ãåœåèŠåã«åºã¥ããŠåãèªåçã«çæããå Žåã«ç¹ã«åœ¹ç«ã¡ãŸããäŸãã°ãã€ãã³ãåããã¢ã¯ã·ã§ã³åãå°åºãããããã®éãå¯èœã§ãã
ãã³ãã¬ãŒããªãã©ã«åã®å®çšçãªã¢ããªã±ãŒã·ã§ã³
- APIãšã³ããã€ã³ãã®å®çŸ©: äžèšã§ç€ºããããã«ãå³å¯ãªåå¶çŽãæã€APIãšã³ããã€ã³ããå®çŸ©ããŸãã
- ã€ãã³ãåŠç: ç¹å®ã®ãã¬ãã£ãã¯ã¹ãšãµãã£ãã¯ã¹ãæã€ã€ãã³ãåã®åãäœæããŸãã
- CSSã¯ã©ã¹ã®çæ: ã³ã³ããŒãã³ãåãšç¶æ ã«åºã¥ããŠCSSã¯ã©ã¹åãçæããŸãã
- ããŒã¿ããŒã¹ã¯ãšãªã®æ§ç¯: ããŒã¿ããŒã¹ã¯ãšãªãæ§ç¯ããéã®åå®å šæ§ã確ä¿ããŸãã
åœéçãªäŸïŒéè²šã®æžåŒèšå®
è€æ°ã®é貚ããµããŒãããéèã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããŠãããšæ³åããŠã¿ãŠãã ããããã³ãã¬ãŒããªãã©ã«åã䜿çšããŠãæ£ããéè²šã®æžåŒèšå®ã匷å¶ã§ããŸãã
type CurrencyCode = "USD" | "EUR" | "GBP" | "JPY";
type CurrencyFormat = `${number} ${T}`;
const priceUSD: CurrencyFormat<"USD"> = "100 USD"; // Valid
const priceEUR: CurrencyFormat<"EUR"> = "50 EUR"; // Valid
// const priceInvalid: CurrencyFormat<"USD"> = "100 EUR"; // Error: Type 'string' is not assignable to type '`${number} USD`'.
function formatCurrency(amount: number, currency: T): CurrencyFormat {
return `${amount} ${currency}`;
}
const formattedUSD = formatCurrency(250, "USD"); // Type: "250 USD"
const formattedEUR = formatCurrency(100, "EUR"); // Type: "100 EUR"
ãã®äŸã§ã¯ãé貚ã®å€ãåžžã«æ£ããé貚ã³ãŒãã§ãã©ãŒããããããããšãä¿èšŒããæœåšçãªãšã©ãŒãé²ããŸãã
æ¡ä»¶åãžã®æ·±æã
æ¡ä»¶åã¯TypeScriptã®åã·ã¹ãã ã«åå²ããžãã¯ãå°å ¥ããä»ã®åã«äŸåããåãå®çŸ©ã§ããããã«ããŸãããã®æ©èœã¯ãéåžžã«æè»ã§åå©çšå¯èœãªåå®çŸ©ãäœæããã®ã«éåžžã«åŒ·åã§ãã
åºæ¬çãªæ§æãšäœ¿çšæ³
æ¡ä»¶åã¯ãinferããŒã¯ãŒããšäžé
æŒç®åïŒcondition ? trueType : falseTypeïŒã䜿çšããŠåã®æ¡ä»¶ãå®çŸ©ããŸãã
type IsString = T extends string ? true : false;
type StringCheck = IsString; // type StringCheck = true
type NumberCheck = IsString; // type NumberCheck = false
ãã®äŸã§ã¯ãIsStringã¯Tãstringã«å²ãåœãŠå¯èœãã©ããããã§ãã¯ããæ¡ä»¶åã§ããå²ãåœãŠå¯èœãªå Žåãåã¯trueã«è§£æ±ºãããããã§ãªãå Žåã¯falseã«è§£æ±ºãããŸãã
inferããŒã¯ãŒã
inferããŒã¯ãŒãã䜿çšãããšãããåããåãæœåºã§ããŸããããã¯ã颿°åãé
ååã®ãããªè€éãªåãæ±ãå Žåã«ç¹ã«åœ¹ç«ã¡ãŸãã
type ReturnType any> = T extends (...args: any) => infer R ? R : any;
function add(a: number, b: number): number {
return a + b;
}
type AddReturnType = ReturnType; // type AddReturnType = number
ãã®äŸã§ã¯ãReturnTypeã¯é¢æ°åTã®æ»ãå€ãæœåºããŸããæ¡ä»¶åã®infer Réšåã¯æ»ãå€ãæšè«ãããããå倿°Rã«å²ãåœãŠãŸããTã颿°åã§ãªãå Žåãåã¯anyã«è§£æ±ºãããŸãã
åé æ¡ä»¶å (Distributive Conditional Types)
æ¡ä»¶åã¯ããã§ãã¯ãããåã裞ã®åãã©ã¡ãŒã¿ã§ããå Žåã«åé åã«ãªããŸããããã¯ãæ¡ä»¶åããŠããªã³åã®åã¡ã³ããŒã«åå¥ã«é©çšãããããšãæå³ããŸãã
type ToArray = T extends any ? T[] : never;
type NumberOrStringArray = ToArray; // type NumberOrStringArray = string[] | number[]
ãã®äŸã§ã¯ãToArrayã¯åTãé
ååã«å€æããŸããTã裞ã®åãã©ã¡ãŒã¿ïŒä»ã®åã§ã©ãããããŠããªãïŒã§ãããããæ¡ä»¶åã¯numberãšstringã«åå¥ã«é©çšãããnumber[]ãšstring[]ã®ãŠããªã³ãçµæãšããŠåŸãããŸãã
æ¡ä»¶åã®å®çšçãªã¢ããªã±ãŒã·ã§ã³
- æ»ãå€ã®åã®æœåº: äžèšã§ç€ºããããã«ã颿°ã®æ»ãå€ã®åãæœåºããŸãã
- ãŠããªã³åããã®åã®ãã£ã«ã¿ãªã³ã°: ãŠããªã³ããç¹å®ã®åã®ã¿ãå«ãåãäœæããŸãã
- ãªãŒããŒããŒãããã颿°åã®å®çŸ©: å ¥ååã«åºã¥ããŠç°ãªã颿°åãäœæããŸãã
- åã¬ãŒãã®äœæ: 倿°ã®åãçµã蟌ã颿°ãå®çŸ©ããŸãã
åœéçãªäŸïŒç°ãªãæ¥ä»åœ¢åŒã®åŠç
äžçã®ç°ãªãå°åã§ã¯ãç°ãªãæ¥ä»åœ¢åŒã䜿çšãããŸãããããã®ããªãšãŒã·ã§ã³ãåŠçããããã«æ¡ä»¶åã䜿çšã§ããŸãã
type DateFormat = "YYYY-MM-DD" | "MM/DD/YYYY" | "DD.MM.YYYY";
type ParseDate = T extends "YYYY-MM-DD"
? { year: number; month: number; day: number; format: "YYYY-MM-DD" }
: T extends "MM/DD/YYYY"
? { month: number; day: number; year: number; format: "MM/DD/YYYY" }
: T extends "DD.MM.YYYY"
? { day: number; month: number; year: number; format: "DD.MM.YYYY" }
: never;
function parseDate(dateString: string, format: T): ParseDate {
// (Implementation would handle different date formats)
if (format === "YYYY-MM-DD") {
const [year, month, day] = dateString.split("-").map(Number);
return { year, month, day, format } as ParseDate;
} else if (format === "MM/DD/YYYY") {
const [month, day, year] = dateString.split("/").map(Number);
return { month, day, year, format } as ParseDate;
} else if (format === "DD.MM.YYYY") {
const [day, month, year] = dateString.split(".").map(Number);
return { day, month, year, format } as ParseDate;
} else {
throw new Error("Invalid date format");
}
}
const parsedDateISO = parseDate("2023-10-27", "YYYY-MM-DD"); // Type: { year: number; month: number; day: number; format: "YYYY-MM-DD"; }
const parsedDateUS = parseDate("10/27/2023", "MM/DD/YYYY"); // Type: { month: number; day: number; year: number; format: "MM/DD/YYYY"; }
const parsedDateEU = parseDate("27.10.2023", "DD.MM.YYYY"); // Type: { day: number; month: number; year: number; format: "DD.MM.YYYY"; }
console.log(parsedDateISO.year); // Access the year knowing it will be there
ãã®äŸã§ã¯ãæå®ãããæ¥ä»åœ¢åŒã«åºã¥ããŠç°ãªãæ¥ä»è§£æé¢æ°ãå®çŸ©ããããã«æ¡ä»¶åã䜿çšããŠããŸããParseDateåã¯ãè¿ããããªããžã§ã¯ãã圢åŒã«åºã¥ããŠæ£ããããããã£ãæã€ããšãä¿èšŒããŸãã
ãã³ãã¬ãŒããªãã©ã«åãšæ¡ä»¶åã®çµã¿åãã
ãã³ãã¬ãŒããªãã©ã«åãšæ¡ä»¶åãçµã¿åãããããšã§ãçã®åãçºæ®ãããŸããããã«ãããä¿¡ããããªãã»ã©åŒ·åãªåæäœãå¯èœã«ãªããŸãã
type EventName = `on${Capitalize}`;
type ExtractEventPayload = T extends EventName
? { type: T; payload: any } // Simplified for demonstration
: never;
type ClickEvent = EventName<"click">; // "onClick"
type MouseOverEvent = EventName<"mouseOver">; // "onMouseOver"
//Example function that takes a type
function processEvent(event: T): ExtractEventPayload {
//In a real implementation, we would actually dispatch the event.
console.log(`Processing event ${event}`);
//In a real implementation, the payload would be based on event type.
return { type: event, payload: {} } as ExtractEventPayload;
}
//Note that the return types are very specific:
const clickEvent = processEvent("onClick"); // { type: "onClick"; payload: any; }
const mouseOverEvent = processEvent("onMouseOver"); // { type: "onMouseOver"; payload: any; }
//If you use other strings, you get never:
// const someOtherEvent = processEvent("someOtherEvent"); // Type is `never`
ãã¹ããã©ã¯ãã£ã¹ãšèæ ®äºé
- ã·ã³ãã«ã«ä¿ã€: 匷åã§ããäžæ¹ã§ããããã®é«åºŠãªåã¯ããã«è€éã«ãªãå¯èœæ§ããããŸããæçããšä¿å®æ§ã远æ±ããŸãããã
- 培åºçãªãã¹ã: å æ¬çãªãŠããããã¹ããäœæããããšã§ãåå®çŸ©ãæåŸ ã©ããã«åäœããããšã確èªããŠãã ããã
- ã³ãŒãã®ããã¥ã¡ã³ãå: é«åºŠãªåã®ç®çãšåäœãæç¢ºã«ææžåããã³ãŒãã®å¯èªæ§ãåäžãããŸãããã
- ããã©ãŒãã³ã¹ã®èæ ®: é«åºŠãªåã®é床ãªäœ¿çšã¯ã³ã³ãã€ã«æéã«åœ±é¿ãäžããå¯èœæ§ããããŸããå¿ èŠã«å¿ããŠã³ãŒãããããã¡ã€ãªã³ã°ããæé©åããŠãã ããã
çµè«
ãã³ãã¬ãŒããªãã©ã«åãšæ¡ä»¶åã¯ãTypeScriptã®åŒ·åãªããŒã«ã§ãããããã®é«åºŠãªåãç¿åŸããããšã§ããã衚çŸåè±ãã§ãä¿å®ãããããåå®å šãªã³ãŒããèšè¿°ã§ããŸãããããã®æ©èœã«ãããåéã®è€éãªé¢ä¿ãæããããå³å¯ãªå¶çŽã匷å¶ããåå©çšæ§ã®é«ãåå®çŸ©ãäœæããããšãå¯èœã«ãªããŸãããããã®ãã¯ããã¯ã掻çšããŠTypeScriptã®ã¹ãã«ãé«ããã°ããŒãã«ãªèŠèŽè åãã®å ç¢ã§ã¹ã±ãŒã©ãã«ãªã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããŸãããã